package tn.redmine.pages;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import tn.redmine.data_models.User;
import core.Pilot;
import core.base.PageBase;

/**
 * Class provides access to web elements and actions on Index page
 */
public class ReportsPage extends PageBase
{
	private static Pilot pilot = new Pilot();
	// Query form
	public static By formQuery = By.id("query_form");
	public static By selectDate = By.id("period");
	public static By selectCriterias = By.id("criterias");
	public static By blockTimeReport = By.id("time-report");
	public static By blockDetailedTimeReport = By.xpath("//*[contains(@class,'time-entries')]");

	public static By blockNextPageTNetworks = By.xpath("//*[@class='pagination']/a[@class='next']");
	public static By blockNextPagePhoenix = By.xpath("//*[@class='pagination']/a[contains(text(),'Next')]");

	public static By blockLastPageTNetworks = By.xpath("(//*[@class='pagination']/a[@class='page'])[last()]");
	public static By blockLastPagePhoenix = By.xpath("(//*[@class='pagination']/a[contains(text(),'Next')]/preceding-sibling::a)[last()]");

	public static By blockDetailedDate()
	{
		return By.xpath("./td[2]");
	}

	public static By blockDetailedActivityName()
	{
		return By.xpath("./td[4]");
	}

	public static By blockDetailedIssueName()
	{
		return By.xpath("./td[6]");
	}

	public static By blockDetailedComment()
	{
		return By.xpath("./td[7]");
	}

	public static By blockDetailedIssues(String p_member)
	{
		return By.xpath("//tr//a[contains(text(),'" + p_member + "')]/parent::td/parent::tr");
	}

	public static By blockCurrentMember(String p_member)
	{
		return By.xpath("//tr[td[contains(text(),'" + p_member + "')]/parent::tr]");
	}

	public static By blockNextMember(String p_currentMember)
	{
		return By.xpath("(//tr[td[contains(text(),'" + p_currentMember + "')]]/following-sibling::tr[td[1][contains(text(),' ')]])[1]");
	}

	public static By blockCurrentMemberName(String p_member)
	{
		return By.xpath("//tr[td[contains(text(),'" + p_member + "')]/parent::tr]/td[1]");
	}

	public static By blockNextMemberName(String p_currentMember)
	{
		return By.xpath("(//tr[td[contains(text(),'" + p_currentMember + "')]]/following-sibling::tr[td[1][contains(text(),' ')]])[1]/td[1]");
	}

	public static By blockIssues(String p_currentMember, String p_nextMember)
	{
		return By
				.xpath("//tr[preceding-sibling::tr[td[contains(text(),'" + p_currentMember
						+ "')]/parent::tr] and following-sibling::tr[td[contains(text(),'" + p_nextMember + "')]/parent::tr]]");
	}

	public static By blockIssueName()
	{
		return By.xpath("./td[3]");
	}

	public static By blockIssueHours()
	{
		return By.xpath("./td[@class='hours'][1]");
	}

	public static By blockActivity()
	{
		return By.xpath("./td[2]");
	}

	/**
	 * Initializes the ReportsPage
	 */
	public ReportsPage(Pilot p_manager)
	{
		super(p_manager);
	}

	public void setDate(String p_period)
	{
		pilot.driver().selectByText(selectDate, p_period);
		pilot.driver().verifySelectedOptionText(selectDate, p_period);
	}

	public void setCriteria(String p_criteriaName)
	{
		pilot.driver().selectByText(selectCriterias, p_criteriaName);
		pilot.driver().waitForVisibility(blockTimeReport, "", true);
	}

	public static Map<Integer, Object[]> getIssues(User p_user)
	{
		Map<Integer, Object[]> reportsTmp = new HashMap<Integer, Object[]>();

		String activity = "";
		String currentMember = pilot.driver().getText(blockCurrentMemberName(p_user.getLastName()));
		String nextMember = pilot.driver().getText(blockNextMemberName(p_user.getLastName()));
		List<WebElement> issues = pilot.driver().getWebElements(blockIssues(currentMember, nextMember));

		pilot.log().info("Issues Total: " + issues.size());

		for (int i = 0; i < issues.size(); i++)
		{
			String activityCurrent = pilot.driver().getWebElementFromWebElement(issues.get(i), blockActivity(), true).getText();

			if (!activityCurrent.equals(""))
			{
				activity = activityCurrent;
			}
			else
			{

				try
				{
					String issue = pilot.string().replaceSubstring(
							pilot.driver().getWebElementFromWebElement(issues.get(i), blockIssueName(), true).getText(), "\"", "");
					Double hours = Double.parseDouble(pilot.driver().getWebElementFromWebElement(issues.get(i), blockIssueHours(), true).getText());
					reportsTmp.put(i, new Object[] { activity, issue, hours, p_user.getCompany() });
				}
				catch (Exception p_ex)
				{
					pilot.log().warn(p_ex.toString());
				}
			}
		}

		return reportsTmp;
	}

	public static Map<Integer, Object[]> getIssuesDetailed(User p_user)
	{
		Map<Integer, Object[]> reportsTmp = new HashMap<Integer, Object[]>();

		int pageNumber = 1;
		int pagesCount = getNumbersOfPages();
		int line = 0;
		List<WebElement> issues = null;
		boolean isIssuesFound = false;

		while (pageNumber <= pagesCount)
		{

			if (!pilot.driver().isElementPresent(blockDetailedIssues(p_user.getLastName())))
			{
				if (isIssuesFound)
				{
					break;
				}
				else
				{
					openNextPage();
					pageNumber++;
				}
			}
			else
			{
				issues = pilot.driver().getWebElements(blockDetailedIssues(p_user.getLastName()));

				pilot.log().info("Issues Total: " + issues.size());

				for (int i = 0; i < issues.size(); i++)
				{
					String date = pilot.driver().getWebElementFromWebElement(issues.get(i), blockDetailedDate(), true).getText();
					String activity = pilot.driver().getWebElementFromWebElement(issues.get(i), blockDetailedActivityName(), true).getText();
					String issue = pilot.string().replaceSubstring(
							pilot.driver().getWebElementFromWebElement(issues.get(i), blockDetailedIssueName(), true).getText(), "\"", "");
					String comment = pilot.driver().getWebElementFromWebElement(issues.get(i), blockDetailedComment(), true).getText();
					Double hours = Double.parseDouble(pilot.driver().getWebElementFromWebElement(issues.get(i), blockIssueHours(), true).getText());

					reportsTmp.put(line, new Object[] { date, activity, issue, comment, hours, p_user.getCompany() });
					line++;
				}

				isIssuesFound = true;
				issues.clear();

				if (pageNumber < pagesCount)
				{
					openNextPage();
					pageNumber++;
				}
				else
				{
					break;
				}
			}

		}

		return reportsTmp;
	}

	public static Map<Integer, Object[]> getDefaultIssues(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			if (entry.getValue()[0].toString().equals("Testing")
					|| entry.getValue()[0].toString().equals("Development")
					|| entry.getValue()[0].toString().equals("Maintenance")
					|| entry.getValue()[0].toString().equals("Consultation")
					|| entry.getValue()[0].toString().equals("act")
					|| entry.getValue()[0].toString().contains("Working off"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "", "" });
			}
		}

		return reports;

	}

	public static Map<Integer, Object[]> getOvertimes(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			if (entry.getValue()[0].toString().contains("Overtime x1"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "x1", "" });
			}
			else if (entry.getValue()[0].toString().contains("Overtime x2"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "x2", "" });
			}
			else if (entry.getValue()[0].toString().contains("Overtime x3"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "x3", "" });
			}
		}

		return reports;

	}

	public static Map<Integer, Object[]> getOthers(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			if (entry.getValue()[0].toString().contains("Vacation"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "", "" });
			}
			else if (entry.getValue()[0].toString().contains("Illness"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "", "" });
			}
			else if (entry.getValue()[0].toString().contains("Skip"))
			{
				reports.put(i++, new Object[] { entry.getValue()[0], entry.getValue()[3], entry.getValue()[1], entry.getValue()[2], "", "" });
			}
		}

		return reports;
	}

	public static Map<Integer, Object[]> getTestingDetailed(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();
		ArrayList<String> issues = new ArrayList<String>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			if (entry.getValue()[1].toString().equals("Testing")
					|| entry.getValue()[1].toString().equals("Development")
					|| entry.getValue()[1].toString().equals("Maintenance")
					|| entry.getValue()[1].toString().equals("Consultation")
					|| entry.getValue()[1].toString().equals("act")
					|| entry.getValue()[1].toString().contains("Working off"))

			{

				String issueName = "[" + entry.getValue()[0] + "] " + entry.getValue()[2];

				for (int x = 0; x < issues.size(); x++)
				{
					if (issues.get(x).equals(issueName))
					{
						issueName += " " + i;
						break;
					}
				}

				issues.add(issueName);

				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "", entry.getValue()[3] });
			}
		}

		return reports;

	}

	public static Map<Integer, Object[]> getOvertimesDetailed(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();
		ArrayList<String> issues = new ArrayList<String>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			String issueName = "[" + entry.getValue()[0] + "] " + entry.getValue()[2];

			for (int x = 0; x < issues.size(); x++)
			{
				if (issues.get(x).equals(issueName))
				{
					issueName += " " + i;
					break;
				}
			}

			issues.add(issueName);

			if (entry.getValue()[1].toString().contains("Overtime x1"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "x1", entry.getValue()[3] });
			}
			else if (entry.getValue()[1].toString().contains("Overtime x2"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "x2", entry.getValue()[3] });
			}
			else if (entry.getValue()[1].toString().contains("Overtime x3"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "x3", entry.getValue()[3] });
			}
		}

		return reports;

	}

	public static Map<Integer, Object[]> getOthersDetailed(Map<Integer, Object[]> reportsTmp)
	{
		Map<Integer, Object[]> reports = new HashMap<Integer, Object[]>();
		ArrayList<String> issues = new ArrayList<String>();

		int i = 0;

		for (Map.Entry<Integer, Object[]> entry : reportsTmp.entrySet())
		{
			String issueName = "[" + entry.getValue()[0] + "] " + entry.getValue()[2];

			for (int x = 0; x < issues.size(); x++)
			{
				if (issues.get(x).equals(issueName))
				{
					issueName += " " + i;
					break;
				}
			}

			issues.add(issueName);

			if (entry.getValue()[1].toString().contains("Vacation"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "", entry.getValue()[3] });
			}
			else if (entry.getValue()[1].toString().contains("Illness"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "", entry.getValue()[3] });
			}
			else if (entry.getValue()[1].toString().contains("Skip"))
			{
				reports.put(i++, new Object[] { entry.getValue()[1], entry.getValue()[5], issueName, entry.getValue()[4], "", entry.getValue()[3] });
			}
		}

		return reports;

	}

	public static void openNextPage()
	{
		if (pilot.driver().isElementPresent(blockNextPageTNetworks))
		{
			pilot.log().info("Open next page");
			pilot.driver().click(blockNextPageTNetworks);
		}
	}

	public static int getNumbersOfPages()
	{
		if (pilot.driver().isElementPresent(blockLastPageTNetworks))
		{
			return Integer.parseInt(pilot.driver().getText(blockLastPageTNetworks));
		}
		else
		{
			return 1;
		}
	}
}